package service

import (
	"api/internal/svc"
	"api/model/order"
	"api/service/cert"
	"api/utils"
	"context"
	"fmt"
	"github.com/go-pay/gopay"
	"github.com/go-pay/gopay/alipay"
	"github.com/go-pay/gopay/wechat/v3"
	"github.com/gomodule/redigo/redis"
	"github.com/zeromicro/go-zero/core/logx"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
	"strconv"
)

// 订单服务
type OrderService struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewOrderService(ctx context.Context, svcCtx *svc.ServiceContext) *OrderService {
	return &OrderService{
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

type Order struct {
	BusinessId   int    `json:"business_id"`
	InnerTradeNo string `json:"inner_trade_no"`
	TradeNo      string `json:"trade_no"`
	Type         int    `json:"type"`
	Amount       string `json:"amount"`
	Status       uint   `json:"status"` // 1=交易创建  2=交易完成 3=交易成功 4=交易关闭
}

var (
	OrderKey     = "order"        // hash
	SalaryCalc   = "moneyCalc"    // 金额累计  满1000扣减服务费用 扣减后值也自动扣减 (单位:分)
	SplitBillBus = "splitBillBus" //  Set 满足分账条件(1000)的商户

)

var (
	ORDER_CREATE  = 1 // 订单创建
	ORDER_SUCCESS = 2 // 订单支付成功

	TYPE_WX  = 1
	TYPE_ALI = 2

	ORDER_TYPE_ORDER_FOOD = 3 // 订单类型:3=扫码点餐
)

// 创建订单
// tradeNo:支付宝或微信预支付单号  amount:金额 discountId:优惠卡id  openId:微信或支付宝openId
func (orderService *OrderService) CreateOrder(sqlConn sqlx.SqlConn, amount int, busId int, innerTradeNo string, tradeNo string, orderType int, createType int, discountId int, openId string, discount int, table string) error {

	// mysql保存订单信息
	orderModel := order.NewOrderModel(sqlConn)
	v := &order.Order{
		BusinessId:   busId,
		InnerTradeNo: innerTradeNo,
		TradeNo:      tradeNo,
		Type:         orderType,
		Amount:       amount,
		Status:       ORDER_CREATE,
		CreateType:   createType,
		CreateAt:     utils.GetCurDateTime(),
		DiscountId:   discountId,
		OpenId:       openId,
		Discount:     discount,
		Table:        table,
	}
	err, _ := orderModel.Insert(orderService.ctx, v)
	return fmt.Errorf("插入order表错误:", err)

}

// 微信分账
// busId:商户id  tradeNo:微信订单id amount:数量(单位分) innerTrade:内部单号
func (orderService *OrderService) WxSplitBill(redis redis.Conn, busId int, tradeNo string, innerTrade string, amount int) {

	ret, _ := redis.Do("HGET", SplitBillBus, busId)
	if ret == nil {
		// 不存在待扣减服务费
		return
	}
	client, err := wechat.NewClientV3(cert.WxMchid, cert.WxSerialNo, cert.WxApiV3Key, cert.WxPrivateKey)
	if err != nil {
		logx.Error("微信支付分账客户端实例化失败,微信订单号:"+tradeNo, err)
		return
	}

	// 启用自动同步返回验签，并定时更新微信平台API证书（开启自动验签时，无需单独设置微信平台API证书和序列号）
	err = client.AutoVerifySign()
	if err != nil {
		logx.Error("微信支付分账客户端自动验签失败,微信单号:"+tradeNo, err)
		return
	}

	var rs []*wechat.ProfitSharingReceiver
	item := &wechat.ProfitSharingReceiver{
		Type:        "PERSONAL_OPENID",
		Account:     orderService.svcCtx.Config.SplitBill.Wx,
		Amount:      amount,
		Description: "特约服务商服务费",
	}
	rs = append(rs, item)
	bm := make(gopay.BodyMap)
	bm.Set("appid", cert.WxAppId).
		Set("transaction_id", tradeNo).
		Set("out_order_no", innerTrade).
		Set("unfreeze_unsplit", true). // 这里要做资金解冻 不然商户无法提现
		Set("receivers", rs)

	_, err = client.V3ProfitShareOrder(orderService.ctx, bm)
	if err == nil {
		// 服务费扣减成功 冲减服务费
		redis.Do("HINCRBY", SplitBillBus, busId, amount)
	} else {
		// 服务费扣减失败
		logx.Error("服务费扣减失败,微信单号:"+tradeNo, err)
	}
}

// 支付宝分账
// busId:商户id  tradeNo:支付宝订单id  amount:数量(单位分) innerTrade:内部单号
func (orderService *OrderService) AliSplitBill(redis redis.Conn, busId int, tradeNo string, innerTrade string, amount int) {
	ret, _ := redis.Do("HGET", SplitBillBus, busId)
	if ret == nil {
		// 不存在待扣减服务费
		return
	}

	client, err := alipay.NewClient(cert.AliAPPID, cert.AliPrivateKey, true)
	if err != nil {
		logx.Error("支付宝分账客户端实例失败", err)
		return
	}
	client.AutoVerifySign(cert.AliPublicRSA2) // 自动验签 待测
	// 模式1:代开发根据商户code获取特约服务商auth TD
	// 模式2(商户自研)
	err = client.SetCertSnByContent(cert.AliAppCer, cert.AliRootCer, cert.AliPublicCer)
	if err != nil {
		logx.Error("支付宝分账自动验签失败", err)
	}
	bm := make(gopay.BodyMap)
	bm.Set("out_request_no", innerTrade)
	bm.Set("trade_no", tradeNo)

	var listParams []*alipay.RoyaltyDetailInfoPojo
	listParams = append(listParams, &alipay.RoyaltyDetailInfoPojo{
		RoyaltyType: "transfer",
		//TransOut:     "2088802095984694",
		//TransOutType: "userId",
		TransInType: "loginName",
		TransIn:     orderService.svcCtx.Config.SplitBill.Ali,
		Amount:      string(amount / 100), // 单位是角
		Desc:        "特约服务商服务费",
	})

	bm.Set("royalty_parameters", listParams)

	_, err = client.TradeOrderSettle(orderService.ctx, bm)
	if err == nil {
		// 服务费扣减成功 冲减服务费
		redis.Do("HINCRBY", SplitBillBus, busId, amount)
	} else {
		// 服务费扣减失败
		logx.Error("服务费扣减失败,支付宝单号:"+tradeNo, err)
	}

}

// 修改订单(目前只是成功后修改单号)
// tradeNo:平台内部单号   status:状态  amount:数值
func (orderService *OrderService) UpdateOrder(sqlConn sqlx.SqlConn, redis redis.Conn, tradeNo string, status int) *order.Order {
	// mysql保存订单信息
	orderModel := order.NewOrderModel(sqlConn)
	v, _ := orderModel.FindOne(orderService.ctx, tradeNo)
	if v != nil {

		v.Status = status
		orderModel.Update(orderService.ctx, v)

		// 注意 amount的单位是分
		maxCount := 1000 * 100
		if v.Amount >= maxCount {

			// 入分账账户
			redis.Do("HINCRBY", SplitBillBus, v.BusinessId, orderService.svcCtx.Config.SplitBill.Money)

		} else {
			ret, _ := redis.Do("HGET", SalaryCalc, v.BusinessId)

			if ret != nil {
				// 存在
				str := string(ret.([]byte))
				num, _ := strconv.ParseInt(str, 10, 64)

				if int(num)+v.Amount >= maxCount {
					// 入分账账户
					redis.Do("HINCRBY", SplitBillBus, v.BusinessId, orderService.svcCtx.Config.SplitBill.Money)

					// 余额入账
					redis.Do("HSET", SalaryCalc, v.BusinessId, maxCount-int(num)-v.Amount)
				}

			}
		}

		return v
	}

	logx.Error("数据单丢失,内部单号:" + tradeNo)
	return nil
}
